//
//  YYSpreadSheetTableView.swift
//  自定义表格
//
//  Created by yao_yu on 15/7/3.
//  Copyright © 2015年 yao_yu. All rights reserved.
//

import UIKit

@objc protocol YYSpreadSheetDataSource{
    var headers:[[String:String]] {get set}
    var datas:[[String:String]] {get set}
}

@objc protocol YYSpreadSheetDelegate{
    optional func spreadSheet(spreadSheet: YYSpreadSheetTableView, didSelectRowAtIndex index:Int)
}

class YYSpreadSheetTableHeaderView: UITableView {
    private let viewBottomLine = CAShapeLayer()

    override init(frame: CGRect, style: UITableViewStyle) {
        super.init(frame: frame, style: style)
        setupViews()
    }

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setupViews()
    }
    
    func setupViews() {
        viewBottomLine.fillColor = UIColor.darkGrayColor().CGColor
        viewBottomLine.strokeColor = nil
        self.layer.addSublayer(viewBottomLine)
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        updateBottomLine()
    }
    
    private func updateBottomLine() {
        let lineHeight:CGFloat = 0.1
        let rect = CGRectMake(0, self.bounds.height - lineHeight, self.bounds.width, lineHeight)
        viewBottomLine.path = UIBezierPath(rect: CGRect(origin: CGPointZero, size: rect.size)).CGPath
        viewBottomLine.frame = rect
    }
}

/*
    需要设置
        columnDefines
        dataSource
        fixedColumns
        tableWidth
*/
class YYSpreadSheetTableView: UIView{
    
    var dataSource:YYSpreadSheetDataSource? {
        didSet {
            _fixedRows =  dataSource == nil ? 0 : dataSource!.headers.count
        }
    }
    var delegate:YYSpreadSheetDelegate?
    
    var fixedRows:Int {
        return _fixedRows
    }
    private var _fixedRows:Int = 0 {
        didSet {
            if _fixedRows != oldValue {
                setNeedsLayout()
            }
        }
    }
    
    var fixedColumns:Int = 0 {
        willSet {
            assertFixedColumns(newValue, columns: columns)
        }
        didSet {
            updateColumnDefines()
            setNeedsLayout()
        }
    }
    
    var tableWidth:CGFloat = 0 {
        didSet {
            setNeedsLayout()
        }
    }
    
    private var _fixedColumnDefines = [(name:String, width:CGFloat)]()
    private var _bodyColumnDefines = [(name:String, width:CGFloat)]()

    var columnDefines = [(name:String, width:CGFloat)]() {
        willSet {
            assertFixedColumns(fixedColumns, columns: newValue.count)
        }
        didSet {
            updateColumnDefines()
            setNeedsLayout()
        }
    }
    private func updateColumnDefines() {
        _fixedColumnDefines[0..<_fixedColumnDefines.count] = columnDefines[0..<fixedColumns]
        _bodyColumnDefines[0..<_bodyColumnDefines.count] = columnDefines[fixedColumns..<columnDefines.count]
    }

    //界面
    private var fixedColumnsTableView = UITableView(frame: CGRectZero)
    private var headerTableView = YYSpreadSheetTableHeaderView(frame: CGRectZero, style: UITableViewStyle.Plain)
    private var bodyTableView = UITableView(frame: CGRectZero)
    private var leftTopTableView = YYSpreadSheetTableHeaderView(frame: CGRectZero, style: UITableViewStyle.Plain)
    private var bodyScrollView:UIScrollView = UIScrollView(frame: CGRectZero)

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupView()
    }

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setupView()
    }
    
    func setupView() {
        for aTable in [fixedColumnsTableView, headerTableView, leftTopTableView, bodyTableView] {
            aTable.separatorStyle = UITableViewCellSeparatorStyle.None
            aTable.delegate = self
            aTable.dataSource = self
            self.addSubview(aTable)
        }
        bodyScrollView.addSubview(bodyTableView)
        self.addSubview(bodyScrollView)
        headerTableView.removeFromSuperview()
        leftTopTableView.removeFromSuperview()
    }
    
    override func layoutSubviews() {
        let fixedColumnsWidth = self.fixedColumnsWidth
        let fixedRowsHeight = self.fixedRowsHeight
        let bodyWidth = self.bounds.width - fixedColumnsWidth
        let bodyHeight = self.bounds.height //- fixedRowsHeight
        
        leftTopTableView.frame = CGRectMake(0, 0, fixedColumnsWidth, fixedRowsHeight)
        fixedColumnsTableView.frame = CGRectMake(0, 0, fixedColumnsWidth, bodyHeight)
        headerTableView.frame = CGRectMake(0, 0, tableWidth, fixedRowsHeight)
        bodyTableView.frame = CGRectMake(0, 0, tableWidth, bodyHeight)
        bodyScrollView.frame = CGRectMake(fixedColumnsWidth, 0, bodyWidth, bodyHeight)
        bodyScrollView.contentSize = bodyTableView.bounds.size
    }
    
    var cellHeight:CGFloat = 40
}

extension YYSpreadSheetTableView: UITableViewDataSource, UITableViewDelegate {
    
    func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        switch tableView {
        case bodyTableView:
            return headerTableView
        case fixedColumnsTableView:
            return leftTopTableView
        default:
            return nil
        }
    }
    
    func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        switch tableView {
        case bodyTableView, fixedColumnsTableView:
            return fixedRowsHeight + 4
        default:
            return 0
        }
    }
    
    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1
    }
    
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        switch tableView {
        case headerTableView, leftTopTableView:
            return fixedRows
        default:
            return dataSource != nil ? dataSource!.datas.count : 0
        }
    }
    
    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        switch tableView {
        case bodyTableView:
            fixedColumnsTableView.selectRowAtIndexPath(indexPath, animated: false, scrollPosition: UITableViewScrollPosition.None)
            delegate?.spreadSheet?(self, didSelectRowAtIndex: indexPath.row)
        case fixedColumnsTableView:
            bodyTableView.selectRowAtIndexPath(indexPath, animated: false, scrollPosition: UITableViewScrollPosition.None)
            delegate?.spreadSheet?(self, didSelectRowAtIndex: indexPath.row)
        default:
            return
        }
    }
    
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cellIdentifier = "cell"
        var cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier) as? YYSpreadSheetTableViewCell
        if cell == nil {
            cell = YYSpreadSheetTableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: cellIdentifier)
        }
        switch tableView {
        case leftTopTableView:
            if _fixedColumnDefines.count > 0 {
                cell?.cellDefines = _fixedColumnDefines
                cell?.rowData = dataSource?.headers[indexPath.row]
                cell?.selectionStyle = UITableViewCellSelectionStyle.None
            }
            
        case headerTableView:
            cell?.cellDefines = _bodyColumnDefines
            cell?.rowData = dataSource?.headers[indexPath.row]
            cell?.selectionStyle = UITableViewCellSelectionStyle.None
            
        case fixedColumnsTableView:
            if _fixedColumnDefines.count > 0 {
                cell?.cellDefines = _fixedColumnDefines
                cell?.rowData = dataSource?.datas[indexPath.row]
            }
            
        default:
            cell?.cellDefines = _bodyColumnDefines
            cell?.rowData = dataSource?.datas[indexPath.row]
        }
        return cell!
    }
}


//Scroll
extension YYSpreadSheetTableView:UIScrollViewDelegate {
    func scrollViewDidScroll(scrollView: UIScrollView) {
        switch scrollView {
        case bodyTableView:
            fixedColumnsTableView.contentOffset.y = scrollView.contentOffset.y
        case fixedColumnsTableView:
            bodyTableView.contentOffset.y = scrollView.contentOffset.y
        default:
            return
        }
    }
}

//约束检测
extension YYSpreadSheetTableView {
    private func assertFixedColumns(fixedColumns:Int, columns:Int) {
        assert(fixedColumns >= 0, "固定列数必须>=0")
        assert(fixedColumns <= columns, "固定列数必须<=总列数")
    }
}

//界面布局
extension YYSpreadSheetTableView{
    private var fixedRowsHeight:CGFloat {
        return cellHeight * CGFloat(fixedRows)
    }
    
    private var fixedColumnsWidth:CGFloat {
        return cellWidths[0..<fixedColumns].sum()
    }
    
    private var bodyCellTotalWidth:CGFloat {
        return cellWidths[fixedColumns..<columnDefines.count].sum()
    }
}

//扩展查询
extension YYSpreadSheetTableView {
    private var columns: Int {
        return columnDefines.count
    }
    
    private var columnDefineWidths:[CGFloat] {
        return columnDefines.map({(item:(name:String, width:CGFloat)) -> CGFloat in
            item.width
        })
    }
    
    private var columnDefinesTotalWidth:CGFloat {
        return columnDefineWidths.sum()
    }
    
    private var cellWidthRatios:[CGFloat] {
        let total:CGFloat = columnDefinesTotalWidth
        return columnDefineWidths.map({ $0 / total })
    }
    
    private var cellWidths:[CGFloat] {
        let unitWidth:CGFloat = tableWidth / columnDefinesTotalWidth
        return columnDefineWidths.map({ $0 * unitWidth })
    }
}
